(in-package :iorek)

(defgeneric template (expr))

(defmethod template (expr)
  (seq *symbol-lang-quote* expr))

(defmethod template ((expr seq))
  (when (not (empty? expr))
    ;;Handle special cases
    (cond
      ((eq (first expr) *symbol-lang-template*) ;;Handle (template (template ...))
       ;;TODO check only 1 arg
       (return-from template (template (template (@ expr 1)))))
      ((eq (first expr) *symbol-lang-insert*) ;;Handle (template (insert ...))
       ;;TODO check only 1 arg
       (return-from template (@ expr 1)))
      ((eq (first expr) *symbol-lang-insert-many*) ;;Handle (template (insert-many ...))
       (error "Unsupported template form: ~A" `(template ,expr)))))
  (let ((result (seq *symbol-lang-append*)) ;;TODO if it becomes longer than max apply args, wrap in an additional (append ...)
        (partial (seq *symbol-lang-list*)))
    (do-seq (elem expr)
      (if (and (seq? elem) (not (empty? elem)))
          (cond
            ((eq (first elem) *symbol-lang-template*)
             ;;TODO check only 1 arg
             (setf partial (with-last partial (template (@ elem 1)))))
            ((eq (first elem) *symbol-lang-insert*)
             (do-seq (item (subseq elem 1))
               (setf partial (with-last partial item))))
            ((eq (first elem) *symbol-lang-insert-many*)
             (setf result (with-last result partial)
                   partial (seq *symbol-lang-list*))
             (do-seq (item (subseq elem 1))
               (setf result (with-last result item))))
            (t (setf partial (with-last partial (template elem)))))
          (setf partial (with-last partial (template elem)))))
    (with-last result partial)))

(defun %template (args env)
  ;;TODO error checking
  (translate-form (template (first args)) env))

(record-definition *symbol-lang-template* '%template :kind :special-operator)